作者:淘气小顽童刘 | 来源:互联网 | 2023-10-12 14:53
篇首语:本文由编程笔记#小编为大家整理,主要介绍了Swift两种方式实现async/await并发模型中任务超时(timeout)的取消相关的知识,希望对你有一定的参考价值。
篇首语:本文由编程笔记#小编为大家整理,主要介绍了Swift 两种方式实现 async/await 并发模型中任务超时(timeout)的取消相关的知识,希望对你有一定的参考价值。
文章目录
- 1. 概览
- 2. Task 超时取消实现之思路
- 3. 第一种实现
- 4. 第二种实现
- 5. 总结
1. 概览
从 Swift 5.5 开始,Apple 引入了新的 async/await 并发模型,我们可以利用它很方便的开发结构化并发代码。
在使用新的并发模型时,一个常见的需求就是任务超时的处理。
我们希望当耗时任务的执行在到达指定时间后自动取消,以免影响用户体验。
在本篇博文中,我们将用两种方法来实现新并发模型中 Task 执行的超时处理。
废话少叙,Let’s Go!!!😉
2. Task 超时取消实现之思路
在 Swift 新 async/await 并发模型中,每个 Task 都会并发执行。所以,要想实现任务超时处理我们只需要同时执行两个任务:
- 第一个是需要完成的任务;
- 第二个是超时监控任务,用它来监听第一个任务是否已超时,如果是则果断取消它;
有的小伙伴可能觉得实现监控任务有点棘手,其实,这超乎意料的简单!
3. 第一种实现
我们只需保存执行的 Task 对象,然后在超时发生时,在第二个超时监控任务中将其取消即可,代码如下:
struct TimedOutError: Error, Equatable
func execute<R>(timeout: TimeInterval, task: &#64;escaping () async throws -> R) async throws -> R
let task &#61; Task
try await task()
Task
try? await Task.sleep(until: .now &#43; .seconds(timeout), clock: .continuous)
task.cancel()
do
return try await task.value
catch
if task.isCancelled
throw TimedOutError()
throw error
正如之前的实现思路&#xff0c;我们依次创建了两个任务&#xff1a;第一个是需要完成的任务&#xff0c;第二个则是超时监控任务&#xff1b;在第二个任务中&#xff0c;一旦超时到达&#xff0c;则取消第一个任务。
Task
do
let r &#61; try await execute(timeout: 3.0)
try await Task.sleep(until: .now &#43; .seconds(3.1), clock: .continuous)
return 11
print("结果是 \\(r)")
catch
print("ERR: \\(error.localizedDescription)")
不过&#xff0c;这样有两个小问题&#xff1a;
- 如果第一个任务在超时前完成&#xff0c;超时监控任务在超时后仍会尝试取消它&#xff1b;
- 当任务执行出现异常时&#xff0c;我们需要判断任务是否被取消&#xff0c;然后再抛出 TimedOutError 错误&#xff1b;
虽然&#xff0c;这并不影响整个 execute() 方法的逻辑&#xff0c;但如果小伙伴们是强迫症患者&#xff0c;我们还有第二种方法可以选择。
4. 第二种实现
第二种方法和前者类似&#xff0c;不过这里我们利用了新并发模型中任务组&#xff08;TaskGroup&#xff09;的特点&#xff1a;其中所有子任务都会并发执行&#xff0c;而且我们可以取消所有子任务。
func execute2<R>(timeout: TimeInterval, task: &#64;escaping () async throws -> R) async throws -> R
try await withThrowingTaskGroup(of: R.self) group in
group.addTask
try await task()
group.addTask
try await Task.sleep(until: .now &#43; .seconds(timeout), clock: .continuous)
throw TimedOutError()
let result &#61; try await group.next()!
group.cancelAll()
return result
如上代码所示&#xff0c;用 TaskGroup 来实现任务超时逻辑更加清晰&#xff0c;而且避免了第一种方法中的两个问题。
更多 Task 任务超时的讨论请参考下面的链接&#xff1a;
Running an async task with a timeout
5. 总结
在本篇博文中&#xff0c;我们用两种方法实现了 Swift 新 async/await 并发模型中任务超时的取消&#xff0c;任君选择。
感谢观赏&#xff0c;再会&#xff01;&#x1f60e;